﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using d = System.Diagnostics;
using System.Reflection;
using AbstraX.ServerInterfaces;
using AssemblyProvider.Web.Entities;
using AbstraX.Generators;
using System.ComponentModel.DataAnnotations;
using System.ServiceModel.DomainServices.Hosting;
using SolutionFramework.Entities;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using AbstraX;
using Polenter.Serialization;
using Utils;
using System.Collections;
using System.Drawing;
using System.Diagnostics;
using Microsoft.Build.Framework;
using ImpromptuInterface;
using DomainServices.Tools;
using System.Drawing.Design;
//using Microsoft.ServiceModel.DomainServices.Tools;

namespace ConsoleApplication4
{
    class TaskHost : ITaskHost, Microsoft.Build.Framework.ILogger, IBuildEngine
    {
        public void Initialize(IEventSource eventSource)
        {
            throw new NotImplementedException();
        }

        public string Parameters
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public void Shutdown()
        {
            throw new NotImplementedException();
        }

        public LoggerVerbosity Verbosity
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public bool BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties, IDictionary targetOutputs)
        {
            throw new NotImplementedException();
        }

        public int ColumnNumberOfTaskNode
        {
            get 
            {
                return 0;
            }
        }

        public bool ContinueOnError
        {
            get { throw new NotImplementedException(); }
        }

        public int LineNumberOfTaskNode
        {
            get 
            {
                return 5;
            }
        }

        public void LogCustomEvent(CustomBuildEventArgs e)
        {
            Console.WriteLine(e.Message); 
        }

        public void LogErrorEvent(BuildErrorEventArgs e)
        {
            Console.WriteLine(e.Message);
        }

        public void LogMessageEvent(BuildMessageEventArgs e)
        {
            Console.WriteLine(e.Message);
        }

        public void LogWarningEvent(BuildWarningEventArgs e)
        {
            Console.WriteLine(e.Message);
        }

        public string ProjectFileOfTaskNode
        {
            get 
            {
                return @"C:\Users\Ken\Documents\Mind Chemistry\SolutionFramework\SolutionFramework\SolutionFramework.csproj";
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var task = new CreateRiaClientFilesTask();
            var serverDirectory = new DirectoryInfo(@"C:\Users\Ken\Documents\Mind Chemistry\SolutionFramework\SolutionFramework.Web\bin");

            task.HostObject = new TaskHost();
            task.BuildEngine = new TaskHost();

            task.ServerProjectPath = @"C:\Users\Ken\Documents\Mind Chemistry\SolutionFramework\SolutionFramework.Web\SolutionFramework.Web.csproj";
            task.OutputPath = @"Bin\Debug\";
            task.ClientProjectPath = @"C:\Users\Ken\Documents\Mind Chemistry\SolutionFramework\SolutionFramework\SolutionFramework.csproj";
            task.Language = "c#";
            //task.CodeGeneratorName = "Microsoft.ServiceModel.DomainServices.Tools.CodeDomClientCodeGenerator";
            task.CodeGeneratorName = "DomainServices.Tools.CodeDomClientCodeGenerator";

            task.ServerAssemblies = serverDirectory.GetFiles("*.dll").Select(f =>
                {
                    return new
                    {
                        ItemSpec = f.FullName
                    }.ActLike<ITaskItem>();
                }).ToArray();

            try
            {
                task.Execute();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.ReadLine();
        }

        class Test
        {
            public System.Type GetProvider(System.Type BaseType)
            {
                foreach (System.Type type in BaseType.Assembly.GetTypes())
                {
                    if (type.GetCustomAttributes(true).AsQueryable().Cast<Attribute>().Any(a => a is EnableClientAccessAttribute))
                    {
                        return type;
                    }
                }

                return null;
            }

            public NodeType? GetElementType(System.Type BaseType)
            {
                foreach (System.Type interfaceType in BaseType.GetInterfaces())
                {
                    if (interfaceType.Name == "IRoot")
                    {
                        return NodeType.Root;
                    }
                    else if (interfaceType.Name == "IElement")
                    {
                        return NodeType.Element;
                    }
                }

                var collectionProperties = new List<PropertyInfo>();

                return null;
            }

            public List<System.Type> GetElementTypes(System.Type BaseType)
            {
                List<System.Type> elementTypes = new List<System.Type>();

                foreach (System.Type type in BaseType.Assembly.GetTypes())
                {
                    foreach (System.Type interfaceType in type.GetInterfaces())
                    {
                        if (interfaceType.Name == "IElement")
                        {
                            elementTypes.Add(type);
                        }
                    }
                }

                return elementTypes;
            }

            public List<System.Type> GetAttributeTypes(System.Type BaseType)
            {
                List<System.Type> attributeTypes = new List<System.Type>();

                foreach (System.Type type in BaseType.Assembly.GetTypes())
                {
                    foreach (System.Type interfaceType in type.GetInterfaces())
                    {
                        if (interfaceType.Name == "IAttribute")
                        {
                            attributeTypes.Add(type);
                        }
                    }
                }

                return attributeTypes;
            }

            public List<System.Type> GetOperationTypes(System.Type BaseType)
            {
                List<System.Type> operationTypes = new List<System.Type>();

                foreach (System.Type type in BaseType.Assembly.GetTypes())
                {
                    foreach (System.Type interfaceType in type.GetInterfaces())
                    {
                        if (interfaceType.Name == "IOperation")
                        {
                            operationTypes.Add(type);
                        }
                    }
                }

                return operationTypes;
            }

            public void ProcessType(System.Type BaseType)
            {
                System.Type providerType = GetProvider(BaseType);
                NodeType? entityType = GetElementType(BaseType);
                List<System.Type> elementTypes = GetElementTypes(BaseType);
                List<System.Type> attributeTypes = GetAttributeTypes(BaseType);
                List<System.Type> operationTypes = GetOperationTypes(BaseType);
                Dictionary<PropertyInfo, System.Type> elementProperties = new Dictionary<PropertyInfo, System.Type>();
                Dictionary<PropertyInfo, System.Type> attributeProperties = new Dictionary<PropertyInfo, System.Type>();
                Dictionary<PropertyInfo, System.Type> operationProperties = new Dictionary<PropertyInfo, System.Type>();
                var interfaceName = Enum.GetName(typeof(NodeType), entityType);

                foreach (MethodInfo methodInfo in providerType.GetMethods())
                {
                    if (methodInfo.ReturnType.Name == "IQueryable`1")
                    {
                        System.Type typeParm = methodInfo.ReturnType.GetGenericArguments().AsQueryable().Cast<System.Type>().FirstOrDefault();
                    }
                    else
                    {
                        foreach (System.Type interfaceType in methodInfo.ReturnType.GetInterfaces())
                        {
                            if (interfaceType.Name == "IRoot")
                            {
                            }
                        }
                    }
                }
                
                if (entityType != null)
                {
                    foreach (var property in BaseType.GetProperties())
                    {
                        // todo - support other collection types

                        if (property.PropertyType.Name == "List`1" && property.PropertyType.IsGenericType)
                        {
                            var argType = property.PropertyType.GetGenericArguments()[0];

                            if (elementTypes.AsEnumerable().Any(e => e.Name == argType.Name))
                            {
                                if (property.GetCustomAttributes(true).AsQueryable().Cast<Attribute>().Any(a => a is AssociationAttribute))
                                {
                                    elementProperties.Add(property, argType);
                                }
                            }
                            else if (attributeTypes.AsEnumerable().Any(e => e.Name == argType.Name))
                            {
                                if (property.GetCustomAttributes(true).AsQueryable().Cast<Attribute>().Any(a => a is AssociationAttribute))
                                {
                                    attributeProperties.Add(property, argType);
                                }
                            }
                            else if (operationTypes.AsEnumerable().Any(e => e.Name == argType.Name))
                            {
                                if (property.GetCustomAttributes(true).AsQueryable().Cast<Attribute>().Any(a => a is AssociationAttribute))
                                {
                                    operationProperties.Add(property, argType);
                                }
                            }
                        }
                    }

                    foreach (var property in BaseType.GetProperties())
                    {
                        string propertyType;

                        if (property.PropertyType.IsGenericType)
                        {
                            var args = String.Join<string>(", ",  property.PropertyType.GetGenericArguments().AsEnumerable().Select(a => a.Name).ToArray<string>());

                            propertyType = property.PropertyType.Name;
                            propertyType = propertyType.Substring(0, propertyType.IndexOf('`'));

                            if (propertyType == "List")
                            {
                                propertyType = "EntitySet";
                            }

                            propertyType = propertyType + "<" + args + ">";
                        }
                        else
                        {
                            propertyType = property.PropertyType.Name;
                        }
                    }

                    foreach (var property in BaseType.GetProperties())
                    {
                        if (property.Name == "RootElements" || property.Name == "ChildElements")
                        {
                            foreach (var childElementType in elementProperties)
                            {
                                var str = childElementType.Key.Name + childElementType.Value.Name;
                            }
                        }
                    }
                }
            }
        }
    }
}
